package com.mingqijia.gassafety.authority.dal.provider;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mingqijia.gassafety.authority.api.resp.config.DictionaryRespDTO;
import com.mingqijia.gassafety.authority.dal.command.*;
import com.mingqijia.gassafety.authority.dal.handler.ConfigureTranslator;
import com.mingqijia.gassafety.db.entity.auth.CompanyEntry;
import com.mingqijia.gassafety.db.entity.auth.ParamConfigEntry;
import com.mingqijia.gassafety.db.mapper.auth.ParamConfigMapper;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.cqrs.QueryHandler;
import com.mingqijia.gassafety.shared.enums.ParamType;
import com.mingqijia.gassafety.shared.enums.RunningState;
import com.mingqijia.gassafety.shared.enums.YesNoEnum;
import com.mingqijia.gassafety.shared.utils.ApplicationUtils;
import com.mingqijia.gassafety.shared.handler.GlobalAuthenticationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 配置信息CU操作(C-create,U-update)
 * @author Damon S.
 * @version v1.0.1
 * @date 2021年04月12日 13:30
 */
@Slf4j
@Component
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ConfigureProvider extends ServiceImpl<ParamConfigMapper, ParamConfigEntry> implements QueryHandler<ParamConfigEntry> {

    private final ConfigureTranslator translator;
    private final CompanyProvider provider;

    public Integer checkDuplication(String name, String code) {
        QueryWrapper<ParamConfigEntry> queryClause = new QueryWrapper<>();
        if (StringUtils.hasText(name)) {
            queryClause.lambda().eq(ParamConfigEntry::getName, name)
                    .eq(ParamConfigEntry::getSpId, ApplicationUtils.getHeaderSpId());
            if (!Objects.equals(Constants.INT_ZERO, this.count(queryClause))) {
                return Constants.INT_ONE;
            }
        }
        if (StringUtils.hasText(code)) {
            queryClause.clear();
            queryClause.lambda().eq(ParamConfigEntry::getCode, code)
                    .eq(ParamConfigEntry::getSpId, ApplicationUtils.getHeaderSpId());
            if (!Objects.equals(Constants.INT_ZERO, this.count(queryClause))) {
                return Constants.INT_TWO;
            }
        }
        // 无重复
        return Constants.INT_ZERO;
    }

    public ParamConfigEntry getConfigByKey(String configKey, ParamType type, String spId) {
        LambdaQueryWrapper<ParamConfigEntry> clause = new LambdaQueryWrapper<>();
        clause.eq(ParamConfigEntry::getState, RunningState.RUNNING.getCode())
                .eq(ParamConfigEntry::getSpId, spId)
                .eq(ParamConfigEntry::getType, type.getCode())
                .eq(ParamConfigEntry::getCode, configKey)
                .eq(ParamConfigEntry::getIsDeleted, YesNoEnum.N.getCode());
        ParamConfigEntry entry = this.getOne(clause);

        if (Objects.nonNull(entry) && (entry.getScope().contains(spId)
                || Objects.equals(entry.getScope(), Constants.STR_ONE))) {
            return entry;
        }
        return null;
    }

    public boolean checkConfigExistsBySpId(String spId) {
        QueryWrapper<ParamConfigEntry> queryClause = new QueryWrapper<>();
        queryClause.lambda().eq(ParamConfigEntry::getSpId, spId)
                .eq(ParamConfigEntry::getType, ParamType.DICTIONARY.getCode())
                .eq(ParamConfigEntry::getIsDeleted, YesNoEnum.N.getCode());
        return count(queryClause) > Constants.INT_ZERO;
    }

    public Page<ParamConfigEntry> find(QueryParamConfigCommand command) {
        LambdaQueryWrapper<ParamConfigEntry> queryClause = new LambdaQueryWrapper<>();
        Optional.ofNullable(command.getType()).ifPresent(
                type -> queryClause.eq(ParamConfigEntry::getType, type.getCode())
        );
        Optional.ofNullable(command.getName()).ifPresent(
                name -> queryClause.like(ParamConfigEntry::getName, name)
        );
        Optional.ofNullable(command.getState()).ifPresent(
                state -> queryClause.eq(ParamConfigEntry::getState, state.getCode())
        );
        Optional.ofNullable(command.getCode()).ifPresent(
                code -> queryClause.like(ParamConfigEntry::getCode, code)
        );
        Optional.ofNullable(command.getValue()).ifPresent(
                value -> queryClause.eq(ParamConfigEntry::getValue, value)
        );
        Optional.ofNullable(command.getScope()).ifPresent(
                scope -> queryClause.like(ParamConfigEntry::getScope, scope)
        );
        Optional.ofNullable(command.getConfigurable()).ifPresent(
                config -> queryClause.eq(
                        ParamConfigEntry::getConfigurable, config.getCode())
        );
        // 判断是全平台 还是 有使用范围
        if (StringUtils.isEmpty(command.getScope()) && !StringUtils.isEmpty(command.getSpId())) {
            queryClause.and(qw -> qw.like(ParamConfigEntry::getScope, command.getSpId())
                    .or().eq(ParamConfigEntry::getScope, Constants.STR_ONE));
        }
        String workingSpId = StringUtils.isEmpty(command.getSpId()) ?
                ApplicationUtils.getHeaderSpId() : command.getSpId();
        queryClause.eq(ParamConfigEntry::getSpId, workingSpId)
                .eq(ParamConfigEntry::getIsDeleted, YesNoEnum.N.getCode())
                .orderByDesc(ParamConfigEntry::getCreatedAt);
        return this.page(createPage(command), queryClause);
    }

    /** 构建前端显示结构 */
    public List<DictionaryRespDTO> buildRespDTO(List<ParamConfigEntry> entries) {
        if (CollectionUtils.isEmpty(entries)) {
            return Collections.emptyList();
        }
        List<DictionaryRespDTO> records = translator.toDictRespDTO(entries);
        records.forEach(item -> {
            item.setScopeType(Constants.INT_TWO);
            if (item.getScope().contains(String.valueOf(Constants.INT_ONE))) {
                item.setScopeCn("全平台");
                item.setScopeType(Constants.INT_ONE);
            }
            List<CompanyEntry> companies = provider.listByIds(item.getScope());
            if (!CollectionUtils.isEmpty(companies)) {
                StringBuilder builder = new StringBuilder();
                companies.forEach(
                        company -> builder.append(Constants.STR_COMMA).append(company.getName())
                );
                item.setScopeCn(builder.substring(Constants.INT_ONE));
            }
        });
        return records;
    }

    @Transactional(rollbackFor = Exception.class)
    public String create(CreateParamConfigCommand command) {
        if (ObjectUtils.isEmpty(command.getState())) {
            command.setState(RunningState.RUNNING);
        }
        this.attachOperator2Command(command);
        if (ObjectUtils.isEmpty(command.getConfigurable())) {
            command.setConfigurable(YesNoEnum.Y);
        }

        QueryWrapper<ParamConfigEntry> queryClause = new QueryWrapper<>();
        queryClause.lambda().eq(ParamConfigEntry::getSpId, command.getSpId())
                .eq(ParamConfigEntry::getType, command.getType().getCode())
                .eq(ParamConfigEntry::getIsDeleted, YesNoEnum.N.getCode())
                .and(qw -> qw.eq(ParamConfigEntry::getName, command.getName())
                        .or().eq(ParamConfigEntry::getCode, command.getCode()));

        if (!Objects.equals(Constants.INT_ZERO, this.count(queryClause))) {
            log.error("该配置已存在[name={}]", command.getName());
            throw new GlobalAuthenticationException("重复，请重新输入");
        }
        ParamConfigEntry entry = translator.toEntry(command);
        if (!this.save(entry)) {
            throw new GlobalAuthenticationException("创建配置失败");
        }
        //企业级操作日志
//        LogVO vo = new LogVO();
//        StringBuilder stringBuilder = new StringBuilder();
//        String detail = LogUtil.addOrDeleteEntity(entry, ParamConfigEntry.class);
//        stringBuilder.append(detail);
//        vo.setDetail(stringBuilder.toString());
//        LogRecordAspect.threadLocal.set(vo);
        return entry.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean update(UpdateParamConfigCommand command) {
        this.attachOperator2Command(command);
        this.checkParamExistence(command.getId());

        UpdateWrapper<ParamConfigEntry> updateClause = new UpdateWrapper<>();
        updateClause.lambda().eq(ParamConfigEntry::getId, command.getId())
                .eq(ParamConfigEntry::getSpId, ApplicationUtils.getHeaderSpId());

        ParamConfigEntry entry = translator.toEntry(command);
        return this.update(entry, updateClause);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean remove(RemoveParamConfigCommand command) {
        this.attachOperator2Command(command);
        this.checkParamExistence(command.getId());

        // 执行逻辑删除操作
        UpdateWrapper<ParamConfigEntry> updateClause = new UpdateWrapper<>();
        updateClause.lambda().eq(ParamConfigEntry::getId, command.getId())
                .eq(ParamConfigEntry::getSpId, ApplicationUtils.getHeaderSpId());

        ParamConfigEntry entry = translator.toEntry(command);
        entry.setIsDeleted(YesNoEnum.Y.isFlag());

        return this.update(entry, updateClause);
    }

    private void checkParamExistence(String paramId) {
        QueryWrapper<ParamConfigEntry> queryClause = new QueryWrapper<>();
        queryClause.lambda().eq(ParamConfigEntry::getId, paramId)
                .eq(ParamConfigEntry::getSpId, ApplicationUtils.getHeaderSpId());

        if (this.count(queryClause) < Constants.INT_ONE) {
            throw new GlobalAuthenticationException("本企业下不存在该配置");
        }
    }
}
